﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Text.RegularExpressions;
using System.Diagnostics;
using GCELibrary.Current;
using System.IO;
using ZF.BLL;
namespace gather.gt
{
    public abstract class gtbase
    {
        public virtual string Domain { get; set; }
        public abstract string[] Paths { get; }
        public virtual string[] Pages { get; set; }
        public virtual string RegFile { get; set; }
        public virtual string TypeName { get; set; }
        public virtual string MTitle { get; set; }
        public virtual string MBody { get; set; }
        public HttpClient HttpClient { get { return new HttpClient(); } }
        public int GatherSleepTime { get; set; }
        public int RegErrorTime { get; set; }
        public bool Reging = false;
        public bool RegTitleRuning1 = false;
        public bool RegTitleRuning2 = false;

        public bool RegBodyRuning1 = false;
        public bool RegBodyRuning2 = false;
        public bool runing = false;
        private Regex _RegexMTitle = null;
        public Regex _RegexMBody = null;
        public virtual Regex RegexMTitle { get { if (_RegexMTitle == null) { _RegexMTitle = new Regex(MTitle); } return _RegexMTitle; } }
        public virtual Regex RegexMBody { get { if (_RegexMBody == null) { _RegexMBody = new Regex(this.MBody); } return _RegexMBody; } }
 
        string[] _lastRegTitle=new string[0];
        InfoModel _lastInfoModel = null;
        Queue<InfoModel> imQueue = new Queue<InfoModel>();
        public void Error(Exception ex, string key)
        {
            if (ex != null)
            {
            }
            else
            {
                Console.WriteLine("==============================================================");
                Console.WriteLine(key);
                Console.WriteLine("==============================================================");
            }
        }
        public void _Debug(object o)
        {
            Log(string.Concat(o));
            Debug.Print(string.Concat(o));
        }
        public void Log(string str)
        {
            Debug.WriteLine(string.Format("{0}---{1}", this.GetType(), str));
            Console.WriteLine(string.Format("{0}---{1}", this.GetType(), str));
        }
        public gtbase()
        {
         
        }
        public virtual void Init()
        {
            GatherSleepTime = 500;
            RegErrorTime = 1000;
            LoadRegCfg();

            if (Pages == null)
            {
                Pages = new string[] { "f0", "f50", "f100" };
            }
        }
        public void LoadRegCfg()
        {
            var lines = System.IO.File.ReadAllLines("gt\\" + RegFile, Encoding.Unicode);
            MTitle = lines[0];
            MBody = lines[1];
        }
        public void Start()
        {
            runing = true;
            new Thread(PubSiteThread).Start();
            Log("开始采集");
            Log("获取urls");
            var urls = GetUrls();
            Log(string.Format("获取urls成功,数量:{0})", urls.Length));
            Log("获取pages");
            var pages = GetPages(urls);

            if (pages.Length == 0)
                Log(string.Format("获取pages失败,数量:{0})", pages.Length));
            else
                Log(string.Format("获取pages成功,数量:{0})", pages.Length));
            Log("获取titles");
            var titles = RTitle(pages);
            if (titles.Length == 0)
                Log(string.Format("获取titles失败,数量:{0})", titles.Length));
            else
                Log(string.Format("获取titles成功,数量:{0})", titles.Length));
            Log("开始RBody");
            RBody(titles);
            PubSite(imQueue.ToList());
            Log("完成RBody");
            runing = false;

        }
        public void SetThread(Thread thread)
        {
        }

        public string[] GetUrls()
        {
            var result = new List<string>();
            foreach (var path in Paths)
            {
                foreach (var page in Pages)
                {
                    result.Add(string.Format(@"{0}/{1}/{2}", Domain, path, page));
                    return result.ToArray();
                }
            }
            return result.ToArray();
        }
        public string[] GetPages(string[] urls)
        {
            var result = new List<string>();
            foreach (var url in urls)
            {
                try
                {
                    var html = HttpClient.GetSrc(url);
                    result.Add(html);
                    Thread.Sleep(1000);
                }
                catch (Exception ex)
                {
                    Error(ex, "public string[] GetPages(string[] urls)");
                }
            }
            return result.ToArray();
        }
        public string[] RTitle(string[] pages)
        {
            var result = new List<string>();
            foreach (var page in pages)
            {
                try
                {
                    Thread thread = null;
                    RegTitleRuning2 = true;
                    RegTitleRuning1 = false;
                    var lastTime = DateTime.Now;
                    _lastRegTitle = new string[] { };
                    while (RegTitleRuning2 || RegTitleRuning1)
                    {

                        if (!RegTitleRuning1)
                        {
                            RegTitleRuning1 = true;
                            if (RegTitleRuning2)
                            {
                                thread = new Thread(new ParameterizedThreadStart(RTitle));
                                SetThread(thread);
                                thread.Start(page);
                                RegTitleRuning2 = false;
                            }
                        }
                        else
                        {
                            if (lastTime.AddMilliseconds(this.RegErrorTime) < DateTime.Now)
                            {
                                thread.Abort();
                                RegTitleRuning2 = false;
                                RegTitleRuning1 = false;
                                break;
                            }

                        }
                        //result.AddRange(titles);
                        Thread.Sleep(1000);
                    }
                    result.AddRange(_lastRegTitle);
                    Thread.Sleep(GatherSleepTime);
                }
                catch (Exception ex)
                {
                    Error(ex, "public string[] RTitle(string[] pages)");
                }
            }
            return result.ToArray();

        }
        public void RTitle(object obj)
        {
            string html = (string)obj;
            var ms=RegexMTitle.Matches(html);
            var result = new List<string>();
            foreach (Match m in ms)
            {
                try
                {
                    var item = m.Groups[1].Value;
                    result.Add(this.Domain + "/" + item);
                }catch(Exception ex)
                {
                }
                
            }
            RegTitleRuning1 = false;
            _lastRegTitle = result.ToArray();
        }
        
        public string GetBody(string html)
        {
            return HttpClient.GetSrc(html);
        }
        public void RBody(string[] titles)
        {
            foreach (var title in titles)
            {
                
                try
                {var body = GetBody(title);
                    Thread thread = null;
                    RegBodyRuning2 = true;
                    RegBodyRuning1 = false;
                    var lastTime = DateTime.Now;
                    _lastInfoModel = null;
                    while (RegBodyRuning2 || RegBodyRuning1)
                    {
                        if (!RegBodyRuning1)
                        {
                            RegBodyRuning1 = true;
                            if (RegBodyRuning2)
                            {
                                thread = new Thread(new ParameterizedThreadStart(RBody));
                                SetThread(thread);
                                thread.Start(new string[] { body,title });
                                RegBodyRuning2 = false;
                            }
                            else
                                break;
                        }
                        else
                        {
                            if (lastTime.AddMilliseconds(this.RegErrorTime) < DateTime.Now)
                            {
                                thread.Abort();
                                RegBodyRuning2 = false;
                                RegBodyRuning1 = false;
                                _Debug("失败" + title);
                                break;
                            }
                        }

                        //if (_lastInfoModel != null)
                        //    imQueue.Enqueue(_lastInfoModel);
                        //result.AddRange(titles);
                        Thread.Sleep(1000);
                    }

                    Thread.Sleep(GatherSleepTime);
                }
                catch (Exception ex)
                {
                    Error(ex, "public void RBody(string[] titles)");
                }
            }

        }
        public void RBody(object obj)
        {
            var strs = (string[])obj;
            string html = strs[0];

            var m = RegexMBody.Match(html);
            var im = GetInfoModel(m);
            if (im != null)
            {
                im.key = strs[1];
                im.type = this.TypeName;
                _lastInfoModel = im;
                imQueue.Enqueue(_lastInfoModel);
            }
            RegBodyRuning1 = false;
        }
        public int GetAreaId(string str)
        {
            var cityName = this.Domain.Replace("http://", "").Replace(".ganji.com/", "");
            var city = CityTemplate.FirstOrDefault(p => p.Key == cityName).Value;
            if (city == null)
            {
                _Debug("未找到city"); return 0;
            }
            var area = city.Childs.FirstOrDefault(p => p.Name == str + "区");
            if (area == null)
            {
                _Debug("未找到area" + str); return 0;
            }
            return area.Id;
        }
        public abstract InfoModel GetInfoModel(Match m);
       


        public void PubSiteThread()
        {
            while (runing&&false)
            {

                if (imQueue.Count > 10)
                {
                    List<InfoModel> list = new List<InfoModel>();
                    for (int i = 0; i < 10; i++)
                    {
                        list.Add(imQueue.Dequeue());
                    }

                    PubSite(list);
                }
                Thread.Sleep(1000);
            }
        }
        public void PubSite(List<InfoModel> list)
        {
            ServiceReference1.WebServiceSoapClient wc = new gather.ServiceReference1.WebServiceSoapClient();
            foreach (var item in list)
            {
                wc.GatherInfo(item.JsonConvert());
                //Log(wc.GatherInfo(item.JsonConvert()) ? "更新成功" : "更新失败");
                
            }
        }


        static Dictionary<string, SimpleTree<int>> _CityTemplate = null;
        public static Dictionary<string, SimpleTree<int>> CityTemplate
        {
            get
            {
                if (_CityTemplate == null) 
                    _CityTemplate =getCityTemplate(); 
                return _CityTemplate;
            }
        }
        public static List<SimpleTree<int>> cityTree = File.ReadAllText("city.txt").JsonConvert<List<SimpleTree<int>>>();
        public static Dictionary<string, SimpleTree<int>> getCityTemplate()
        {
            var allCityList = @"
gz-广州市
sz-深圳市
          dg-东莞市
          zhuhai-珠海市
          shantou-汕头市
          foshan-佛山市
          jiangmen-江门市
          zhongshan-中山市
          huizhou-惠州市
          maoming-茂名市
          shaoguan-韶关市
          zhanjiang-湛江市
          zhaoqing-肇庆市
          meizhou-梅州市
          shanwei-汕尾市
          heyuan-河源市
          yangjiang-阳江市
          qingyuan-清远市
          chaozhou-潮州市
          jieyang-揭阳市
          yunfu-云浮市".Replace(" ", "").Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries)
                   .Select(p => new Keyword<string>() { Key = p.Split('-')[0], Text = p.Split('-')[1] }).ToList();
            Dictionary<string, SimpleTree<int>> dic = new Dictionary<string, SimpleTree<int>>();
            foreach (var c in allCityList)
            {
                var ct = cityTree.FirstOrDefault(p => p.Name == c.Text);
                if (ct != null)
                    dic[c.Key] = ct;
                else
                {
                    throw new Exception();
                }
            }

            return dic;

        }

    }
     

}
